package annotation

import (
	"go/ast"
)

// SingleFileEntryVisitor 这部分和课堂演示差不多，但是我建议你们自己试着写一些
type SingleFileEntryVisitor struct {
	file *fileVisitor
}

func (s *SingleFileEntryVisitor) Get() File {
	if s.file == nil {
		return File{}
	}
	return s.file.Get()
}

func (s *SingleFileEntryVisitor) Visit(node ast.Node) ast.Visitor {
	file, ok := node.(*ast.File)
	if !ok {
		return s
	}
	s.file = &fileVisitor{ans: newAnnotations(file, file.Doc)}
	return s.file
}

type fileVisitor struct {
	ans     Annotations[*ast.File]
	types   []*typeVisitor
	visited bool
}

func (f *fileVisitor) Get() File {
	types := make([]Type, 0, len(f.types))
	for _, typ := range f.types {
		types = append(types, Type{Annotations: typ.ans, Fields: typ.fields})
	}
	return File{Annotations: f.ans, Types: types}
}

func (f *fileVisitor) Visit(node ast.Node) ast.Visitor {
	typ, ok := node.(*ast.TypeSpec)
	if !ok {
		return f
	}
	res := &typeVisitor{
		ans:    newAnnotations(typ, typ.Doc),
		fields: make([]Field, 0),
	}
	f.types = append(f.types, res)
	return res
}

type File struct {
	Annotations[*ast.File]
	Types []Type
}

type typeVisitor struct {
	ans    Annotations[*ast.TypeSpec]
	fields []Field
}

func (t *typeVisitor) Get() Type {
	return Type{
		Annotations: t.ans,
		Fields:      t.fields,
	}
}

func (t *typeVisitor) Visit(node ast.Node) (w ast.Visitor) {
	fd, ok := node.(*ast.Field)
	if !ok {
		return t
	}
	t.fields = append(t.fields, Field{Annotations: newAnnotations(fd, fd.Doc)})
	return nil
}

type Type struct {
	Annotations[*ast.TypeSpec]
	Fields []Field
}

type Field struct {
	Annotations[*ast.Field]
}
